@@ -1,5 +1,18 @@
Changes for MooseX-Role-Parameterized
+0.18 March 10, 2010
+ * Improve the error message when you leave off the role {} block
+ http://stackoverflow.com/questions/2418177/moose-and-error-messages-the-sun-and-the-moon/2418429
+
+0.17 February 11, 2010
+ * MANIFEST fixes (Karen Etheridge)
+
+0.16 February 4, 2010
+ * Allow specifying custom metaclasses for parameterized
+ roles (Oliver Charles)
+
+ * Documentation improvements (Oliver Charles, Sartak)
+
0.15 January 5, 2010
* Move the guts of MXRPMR::Parameterized into a trait. See
http://www.nntp.perl.org/group/perl.moose/2010/01/msg1294.html (Sartak)
@@ -8,6 +8,7 @@ inc/Module/Install/Metadata.pm
inc/Module/Install/Win32.pm
inc/Module/Install/WriteAll.pm
lib/MooseX/Role/Parameterized.pm
+lib/MooseX/Role/Parameterized/Extending.pod
lib/MooseX/Role/Parameterized/Meta/Parameter.pm
lib/MooseX/Role/Parameterized/Meta/Role/Parameterizable.pm
lib/MooseX/Role/Parameterized/Meta/Role/Parameterized.pm
@@ -35,9 +36,9 @@ t/015-compose-keywords.t
t/016-trait.t
t/017-current_metaclass.t
t/018-parameter-roles.t
+t/019-custom-metaclass.t
t/100-erroneous-keywords.t
t/101-alias-excludes.t
t/102-nested.t
t/150-composite-role-application.t
-t/200-curried-parameterized-role.t
t/lib/Bar.pm
@@ -25,4 +25,4 @@ requires:
perl: 5.8.1
resources:
license: http://dev.perl.org/licenses/
-version: 0.15
+version: 0.18
@@ -6,11 +6,10 @@ name 'MooseX-Role-Parameterized';
all_from 'lib/MooseX/Role/Parameterized.pm';
githubmeta;
-requires 'Moose' => '0.78';
-test_requires 'Test::Moose';
-test_requires 'Test::More' => '0.88';
-
-build_requires 'Test::Exception' => '0.27';
+requires 'Moose' => '0.78';
+test_requires 'Test::Moose';
+test_requires 'Test::More' => '0.88';
+test_requires 'Test::Exception' => '0.27';
WriteAll;
@@ -0,0 +1,40 @@
+=pod
+
+=head1 NAME
+
+MooseX::Role::Parameterized::Extending - extending MooseX::Role::Parameterized roles
+
+=head1 DESCRIPTION
+
+There are heaps of useful modules in the MooseX namespace that you can use to
+make your roles more powerful. However, they do not always work out of the box
+with MooseX::Role::Parameterized, but it's fairlystraight forward to achieve
+the functionality you desire.
+
+MooseX::Role::Parameterized was designed to be extensible, and it is now
+possible to apply custom traits to the generated role, giving them the
+functionality provided in MooseX modules. In this example, we will look at
+applying the fake trait 'MooseX::MagicRole' to a parameterized role.
+
+The first we need to do is define a new metaclass for our parameterized role.
+To get MooseX::Role::Parameterized to apply this metaclass to our roles, we
+need a little bit of glue first:
+
+ package MyApp::Meta::Role::Parameterizable;
+ use Moose;
+ extends 'MooseX::Role::Parameterized::Meta::Role::Parameterizable';
+ sub parameterized_role_metaclass { 'MyApp::Meta::Role::Parameterized' }
+
+Now we can take advantage of this by specifying our glue metaclass to
+MooseX::Role::Parameterized:
+
+ package MyApp::Role;
+ use MooseX::Role::Parameterized -metaclass => 'MyApp::Meta::Role::Parameterizable';
+
+ role {
+ }
+
+And there you go! MyApp::Role now has the MooseX::MagicRole trait applied.
+
+=cut
+
@@ -2,7 +2,7 @@ package MooseX::Role::Parameterized::Meta::Parameter;
use Moose;
extends 'Moose::Meta::Attribute';
-our $VERSION = '0.15';
+our $VERSION = '0.18';
# This doesn't actually do anything because _process_options does not consult
# the default value of "is". hrm.
@@ -2,7 +2,7 @@ package MooseX::Role::Parameterized::Meta::Role::Parameterizable;
use Moose;
extends 'Moose::Meta::Role';
-our $VERSION = '0.15';
+our $VERSION = '0.18';
use MooseX::Role::Parameterized::Meta::Role::Parameterized;
use MooseX::Role::Parameterized::Meta::Parameter;
@@ -76,10 +76,13 @@ sub generate_role {
? $args{parameters}
: $self->construct_parameters(%{ $args{parameters} });
- confess "A role generator is required to generate roles"
+ confess "A role generator is required to apply parameterized roles (did you forget the 'role { ... }' block in your parameterized role '".$self->name."'?)"
unless $self->has_role_generator;
- my $role = $self->parameterized_role_metaclass->create_anon_role(
+ my $parameterized_role_metaclass = $self->parameterized_role_metaclass;
+ Class::MOP::load_class($parameterized_role_metaclass);
+
+ my $role = $parameterized_role_metaclass->create_anon_role(
genitor => $self,
parameters => $parameters,
);
@@ -3,7 +3,7 @@ use Moose;
extends 'Moose::Meta::Role';
with 'MooseX::Role::Parameterized::Meta::Trait::Parameterized';
-our $VERSION = '0.15';
+our $VERSION = '0.18';
__PACKAGE__->meta->make_immutable;
no Moose;
@@ -1,7 +1,7 @@
package MooseX::Role::Parameterized::Meta::Trait::Parameterized;
use Moose::Role;
-our $VERSION = '0.15';
+our $VERSION = '0.18';
use MooseX::Role::Parameterized::Parameters;
@@ -1,7 +1,7 @@
package MooseX::Role::Parameterized::Parameters;
use Moose;
-our $VERSION = '0.15';
+our $VERSION = '0.18';
__PACKAGE__->meta->make_immutable;
no Moose;
@@ -13,7 +13,7 @@ L<Moose::Cookbook::Roles::Recipe1> for an introduction to L<Moose::Role>.
While combining roles affords you a great deal of flexibility, individual roles
have very little in the way of configurability. Core Moose provides C<alias>
for renaming methods and C<excludes> for ignoring methods. These options are
-primarily (perhaps solely) for disambiguating role conflicts. See
+primarily (perhaps solely) for resolving role conflicts. See
L<Moose::Cookbook::Roles::Recipe2> for more about C<alias> and C<excludes>.
Because roles serve many different masters, they usually provide only the least
@@ -22,7 +22,7 @@ configurability than C<alias> and C<excludes> is required. Perhaps your role
needs to know which method to call when it is done. Or what default value to
use for its C<url> attribute.
-Parameterized roles offer exactly this solution.
+Parameterized roles offer a solution to these (and other) kinds of problems.
=head1 USAGE
@@ -50,8 +50,9 @@ immediately after the role they belong to:
=head3 C<parameter>
Inside your parameterized role, you specify a set of parameters. This is
-exactly like specifying the attributes of a class. Instead of C<has> you use
-the keyword C<parameter>, but your parameters can use any options to C<has>.
+exactly like specifying the attributes of a class. Instead of L<Moose/has> you
+use the keyword C<parameter>, but your parameters can use any options to
+C<has>.
parameter 'delegation' => (
isa => 'HashRef|ArrayRef|RegexpRef',
@@ -61,15 +62,20 @@ the keyword C<parameter>, but your parameters can use any options to C<has>.
You do have to declare what parameters you accept, just like you have to
declare what attributes you accept for regular Moose objects.
+One departure from C<has> is that we create a reader accessor for you by
+default. In other words, we assume C<< is => 'ro' >>. If you do not want an
+accessor, you can use C<< is => 'bare' >>.
+
=head3 C<role>
C<role> takes a block of code that will be used to generate your role with its
-parameters bound. Here is where you declare parameterized components: use
-C<has>, method modifiers, and so on. The C<role> block receives an argument,
-which contains the parameters specified by C<with>. You can access the
-parameters just like regular attributes on that object.
+parameters bound. Here is where you declare components that depend on
+parameters. You can declare attributes, methods, modifiers, etc. The first
+argument to the C<role> is an object containing the parameters specified by
+C<with>. You can access the parameters just like regular attributes on that
+object.
-Each time you compose this parameterized role, the role {} block will be
+Each time you compose this parameterized role, the C<role {}> block will be
executed. It will receive a new parameter object and produce an entirely new
role. That's the whole point, after all.
@@ -112,9 +118,9 @@ can now also choose type, default value, whether it's required, B<traits>, etc.
=item Inform a role of your class' attributes and methods
-Core roles can require only methods with specific names. Now your roles can
-require that you specify a method name you wish the role to instrument, or
-which attributes to dump to a file.
+Core roles can only require methods with specific names chosen by the role. Now
+your roles can demand that the class specifies a method name you wish the role to
+instrument, or which attributes to dump to a file.
parameter instrument_method => (
isa => 'Str',
@@ -7,7 +7,7 @@ use Scalar::Util 'blessed';
use MooseX::Role::Parameterized::Meta::Role::Parameterizable;
-our $VERSION = '0.15';
+our $VERSION = '0.18';
our $CURRENT_METACLASS;
Moose::Exporter->setup_import_methods(
@@ -43,10 +43,10 @@ sub role (&) {
sub init_meta {
my $self = shift;
+ my %options = @_;
+ $options{metaclass} ||= 'MooseX::Role::Parameterized::Meta::Role::Parameterizable';
- return Moose::Role->init_meta(@_,
- metaclass => 'MooseX::Role::Parameterized::Meta::Role::Parameterizable',
- );
+ return Moose::Role->init_meta(%options);
}
sub has {
@@ -226,6 +226,9 @@ There are many possible implementations for parameterized roles (hopefully with
a consistent enough API); I believe this to be the easiest and most flexible
design. Coincidentally, Pugs originally had an eerily similar design.
+See L<MooseX::Role::Parameterized::Extending> for some tips on how to extend
+this module.
+
=head2 Why a parameters object?
I've been asked several times "Why use a parameter I<object> and not just a
@@ -1,7 +1,7 @@
#!/usr/bin/env perl
use strict;
use warnings;
-use Test::More tests => 21;
+use Test::More tests => 22;
use Test::Exception;
my %args;
@@ -136,6 +136,17 @@ throws_ok {
};
} qr/^Attribute \(format\) does not pass the type constraint/;
+throws_ok {
+ package MyRole::Sans::Block;
+ use MooseX::Role::Parameterized;
+
+ parameter 'foo';
+
+ package MyClass::Error::BlocklessRole;
+ use Moose;
+ with 'MyRole::Sans::Block' => {};
+} qr/^\QA role generator is required to apply parameterized roles (did you forget the 'role { ... }' block in your parameterized role 'MyRole::Sans::Block'?)\E/;
+
sub cant_ok {
local $Test::Builder::Level = $Test::Builder::Level + 1;
my $instance = shift;
@@ -0,0 +1,45 @@
+#!/usr/bin/env perl
+use strict;
+use warnings;
+use Test::More tests => 1;
+use Test::Moose;
+
+do {
+ package MyTrait;
+ use Moose::Role;
+};
+
+BEGIN {
+ do {
+ package Parameterized;
+ use Moose;
+ extends 'Moose::Meta::Role';
+ with 'MooseX::Role::Parameterized::Meta::Trait::Parameterized';
+ with 'MyTrait';
+ };
+
+ do {
+ package Parameterizable;
+ use Moose;
+ extends 'MooseX::Role::Parameterized::Meta::Role::Parameterizable';
+ sub parameterized_role_metaclass { 'Parameterized' }
+ };
+}
+
+do {
+ package MyRole;
+ use MooseX::Role::Parameterized -metaclass => 'Parameterizable';
+
+ role {
+ my ($params, %extra) = @_;
+ ::does_ok($extra{operating_on}, 'MyTrait', 'parameterized role should do the MyTrait trait');
+ }
+};
+
+do {
+ package MyClass;
+ use Moose;
+ with 'MyRole';
+};
+
+MyClass->new;
@@ -1,43 +0,0 @@
-#!/usr/bin/env perl
-use strict;
-use warnings;
-use Test::More skip_all => "not implemented yet";
-
-do {
- package YAPC;
- use MooseX::Role::Parameterized;
-
- parameter organizer => (
- isa => 'Str',
- required => 1,
- );
-
- parameter location => (
- isa => 'Str',
- required => 1,
- );
-
- role {
- my $p = shift;
-
- method describe => sub {
- return sprintf 'organized by %s in %s',
- $p->organizer,
- $p->location;
- };
- };
-};
-
-do {
- package YAPC::Asia;
- use MooseX::Role::Parameterized;
-
- # This can't work sanely; if you want the role to be parameterized you need
- # to declare it as such
-# use Moose::Role;
-
- with 'YAPC' => {
- location => 'Tokyo',
- };
-};
-